package gbackup.main;

import gbackup.command.Command;
import gbackup.command.ExitCommand;
import gbackup.command.GetCommand;
import gbackup.command.HelpCommand;
import gbackup.command.LocalChangeDirectoryCommand;
import gbackup.command.LocalListCommand;
import gbackup.command.LocalMakeDirectoryCommand;
import gbackup.command.PutCommand;
import gbackup.command.RemoteChangeDirectoryCommand;
import gbackup.command.RemoteListCommand;
import gbackup.command.VersionCommand;
import gbackup.core.Shell;
import gbackup.error.CommandNotFoundException;

import java.lang.reflect.Constructor;
import java.util.Hashtable;
import java.util.Map;


public class CommandDispatcher {
	Map<String, Class<?>> _commandMap = null;

	public CommandDispatcher() {
		this._commandMap = new Hashtable<String, Class<?>>();
		this.addCommands();
	}

	public void dispatch(Shell shell, String rawCommand) throws CommandNotFoundException, RuntimeException {
		if (rawCommand == null || rawCommand.length() == 0)
			return;

		String commandString = null;
		if (rawCommand.indexOf(' ') == -1)
			commandString = rawCommand;
		else
			commandString = rawCommand.substring(0, rawCommand.indexOf(' '));

		if (!this._commandMap.containsKey(commandString.toLowerCase()))
			throw new CommandNotFoundException(rawCommand);

		Command command = null;
		try {
			Class<?> parameterTypes[] = new Class[] { Shell.class, String.class };
			Class<?> commandClass = (Class<?>) this._commandMap.get(commandString);
			Constructor<?> commandConstructor = commandClass.getConstructor(parameterTypes);
			command = (Command) commandConstructor.newInstance(shell, rawCommand);
		} catch (Exception e) {
			throw new RuntimeException(e.toString());
		}
		command.execute();
	}

	private void addCommands() {
		this._commandMap.put("ls", RemoteListCommand.class);
		this._commandMap.put("lls", LocalListCommand.class);

		this._commandMap.put("cd", RemoteChangeDirectoryCommand.class);
		this._commandMap.put("lcd", LocalChangeDirectoryCommand.class);

//		this._commandMap.put("mkdir", ChangeDirectoryCommand.class);
//		this._commandMap.put("rmdir", ChangeDirectoryCommand.class);
//		this._commandMap.put("rm", ChangeDirectoryCommand.class);
//		this._commandMap.put("mv", ChangeDirectoryCommand.class);
		this._commandMap.put("lmkdir", LocalMakeDirectoryCommand.class);
//		this._commandMap.put("lrmdir", ChangeDirectoryCommand.class);
//		this._commandMap.put("lrm", ChangeDirectoryCommand.class);
//		this._commandMap.put("lmv", ChangeDirectoryCommand.class);

		this._commandMap.put("get", GetCommand.class);
		this._commandMap.put("put", PutCommand.class);

		this._commandMap.put("exit", ExitCommand.class);
		this._commandMap.put("help", HelpCommand.class);
		this._commandMap.put("version", VersionCommand.class);
	}
}
